#include "CUDAVolumeRenderer.h"
#include <cuda.h>
#include <cudaGL.h>
#include <cuda_runtime_api.h>

//#pragma comment(lib, "glew32.lib")
//#pragma comment(lib, "glu32.lib")

//pure virtual destructor of the base class
volumeEngineCoreInterface::~volumeEngineCoreInterface(){}

#include <iostream>
CUDAVolumeRenderer::CUDAVolumeRenderer()
{
		std::cout<<"Render in dll"<< std::endl;
		this->initCUDA();


}

CUDAVolumeRenderer::~CUDAVolumeRenderer()
{
	std::cout<<"CUDAVolumeRenderer destroyed"<<std::endl;
}
//virtual destructor
void CUDAVolumeRenderer::destroyObject()
{
	delete this;
}

bool CUDAVolumeRenderer::InitEngine(int w, int h)
{
	bool isOK = true;
	_width = w; _height = h;



	return isOK;
}

void CUDAVolumeRenderer::Render()
{
	
}

void CUDAVolumeRenderer::RenderToImage()
{
}

void CUDAVolumeRenderer::Resize(int w, int h) 
{
	_width = w; _height = h;


}

void CUDAVolumeRenderer::Refresh() // reload shader etc.
{
}

void CUDAVolumeRenderer::Init1DTF(int dataSize, int tableSize)
{

}

void CUDAVolumeRenderer::Update1DTF(void* buffer=0)
{
}

void CUDAVolumeRenderer::SetViewingParameters(parameterViewing &paraV)
{
	_paraV = paraV;
}
void CUDAVolumeRenderer::SetShadingParameters(parameterShading &paraS)
{
	_paraS = paraS;
}
bool CUDAVolumeRenderer::LoadCoreStatusFromFile(const char* filename)
{
	return false;
}

bool CUDAVolumeRenderer::SaveCoreStatusToFile(const char* filename)
{
	return false;
}

//==========================
bool CUDAVolumeRenderer::loadSingleVolume(const char* filename)
{
	return false;
}



//protected
bool CUDAVolumeRenderer::initCUDA()
{
	bool isOK = _cudaLauncher.InitDriver();
 	isOK &= _cudaLauncher.LoadCudaModule("..\\Debug\\testKernel.cubin");

	//testing
	int N=100;
	int size = N*sizeof(int);
	int* h_A = (int*)malloc(size); 
	memset(h_A,0,size);
	int* h_B = (int*)malloc(size);
	memset(h_B,0,size);
	int* h_C = (int*)malloc(size);
	memset(h_C,0,size);
  	for(int i=0; i<N; i++)
		h_A[i]= 1;

	unsigned int* h_array = (unsigned int*)malloc(4*N*sizeof(unsigned int));

	for(int i=0; i<N*4; i++)
		h_array[i]= 2;

	CUdeviceptr d_A; 
	isOK &= _cudaLauncher.checkError(cuMemAlloc(&d_A, size)); 
	CUdeviceptr d_B; 
	isOK &= _cudaLauncher.checkError(cuMemAlloc(&d_B, size)); 
	CUdeviceptr d_C; 
	isOK &= _cudaLauncher.checkError(cuMemAlloc(&d_C, size)); 

	isOK &= _cudaLauncher.checkError(cuMemcpyHtoD(d_A, h_A, size)); 
	isOK &= _cudaLauncher.checkError(cuMemcpyHtoD(d_B, h_B, size));

	//texture test
	int width = 10;
	int height = 2;
	CUarray texArray;
	CUDA_ARRAY_DESCRIPTOR desc;
	desc.Format = CU_AD_FORMAT_UNSIGNED_INT32;
	desc.NumChannels = 4;
	desc.Width =width;
	desc.Height = height;
	cuArrayCreate(&texArray, &desc);

	//copy mem to texArray
	CUDA_MEMCPY2D copyParam;
	memset(&copyParam, 0, sizeof(copyParam));
	copyParam.dstMemoryType = CU_MEMORYTYPE_ARRAY;
	copyParam.dstArray = texArray;
	copyParam.srcMemoryType = CU_MEMORYTYPE_HOST;
	copyParam.srcHost = h_array;
	copyParam.srcPitch = width * sizeof(unsigned int);
	copyParam.WidthInBytes = copyParam.srcPitch;
	copyParam.Height = height;
	isOK &= _cudaLauncher.checkError(cuMemcpy2D(&copyParam));

	
	CUtexref texRef;
	isOK &= _cudaLauncher.checkError(cuArrayCreate(&texArray, &desc));
	isOK &= _cudaLauncher.checkError(cuModuleGetTexRef(&texRef, _cudaLauncher.getModule(), "tex"));
	//_cudaLauncher.

	
	int offset = 0;
	CUfunction func = _cudaLauncher.getKernelFunction("VecAdd");
	_cudaLauncher.setParamPtr(func,offset, d_A); 
	_cudaLauncher.setParamPtr(func,offset, d_B);
	_cudaLauncher.setParamPtr(func,offset, d_C);
	_cudaLauncher.setParami(func, offset, N);

	int threadsPerBlock = 256; 
	int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; 
	_cudaLauncher.LaunchKernel(func, offset, vec3i(threadsPerBlock,1,1),vec2i(blocksPerGrid,1));

	isOK &= _cudaLauncher.checkError(cuMemcpyDtoH(h_C, d_C, size));

	cuMemFree(d_A);
	cuMemFree(d_B);
	cuMemFree(d_C);

	for(int i=0; i<N; i++)
		printf("%d ", h_C[i]);

	return isOK;
}
